/*
 * CRogueTalents.java
 *
 * Copyright (c) 2009 Giles Millward (Manigra). All rights reserved.
 *
 * This file is part of JRogueDPS.
 *
 * JRogueDPS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * JRogueDPS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with JRogueDPS.  If not, see <http://www.gnu.org/licenses/>.
 */
package talents;

import geardatabase.CDatabase;
import utility.CUtility;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import jroguedps.CGlobal;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentFactory;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import paperdoll.CPaperDoll;

public class CRogueTalents implements ActionListener {

	private HashMap<String, CTalent> m_hashMapTalent;
    private CTalentTree m_talentTree[] = new CTalentTree[3];
    private HashMap<String, CTalentTree> m_talentTreeMap;
    private int m_maxPoints;
    private JButton exportBlizzardButton;
    private JButton exportWowHeadButton;
    private JButton importLinkButton;
    private JButton saveTalentsButton;
    private JButton loadTalentsButton;
    private JButton resetTalentsButton;
    private JLabel pointsRemaining;
    private JLabel totalPoints;
    private JLabel glyphsLabel;

    private JComboBox glyphAComboBox;
    private JComboBox glyphBComboBox;
    private JComboBox glyphCComboBox;

    ArrayList<String> m_glyphs = new ArrayList<String>();

    private String[] m_glyphStrings = new String[] {
                    "None",
                    "Adrenaline Rush",
                    "Ambush",
                    "Backstab",
                    "Blade Flurry",
                    "Cloak of Shadows",
                    "Crippling Poison",
                    "Deadly Throw",
                    "Envenom",
                    "Evasion",
                    "Eviscerate",
                    "Expose Armor",
                    "Fan of Knives",
                    "Feint",
                    "Garrote",
                    "Ghostly Strike",
                    "Gouge",
                    "Hemorrhage",
                    "Hunger for Blood",
                    "Killing Spree",
                    "Mutilate",
                    "Preparation",
                    "Rupture",
                    "Sap",
                    "Shadow Dance",
                    "Sinister Strike",
                    "Slice and Dice",
                    "Sprint",
                    "Tricks of the Trade",
                    "Vigor"};

	public CRogueTalents()
	{
        importLinkButton = new JButton();
        exportBlizzardButton = new JButton();
        exportWowHeadButton = new JButton();
        importLinkButton = new JButton();
        pointsRemaining = new JLabel();
        totalPoints = new JLabel();
        glyphsLabel = new JLabel();
        loadTalentsButton = new JButton();
        saveTalentsButton = new JButton();
        resetTalentsButton = new JButton();
        glyphAComboBox = new javax.swing.JComboBox();
        glyphBComboBox = new javax.swing.JComboBox();
        glyphCComboBox = new javax.swing.JComboBox();

        glyphAComboBox.setModel(new javax.swing.DefaultComboBoxModel(m_glyphStrings));
        glyphBComboBox.setModel(new javax.swing.DefaultComboBoxModel(m_glyphStrings));
        glyphCComboBox.setModel(new javax.swing.DefaultComboBoxModel(m_glyphStrings));

        glyphAComboBox.setBounds(560, 520, 120, 23);
        glyphBComboBox.setBounds(560, 550, 120, 23);
        glyphCComboBox.setBounds(560, 580, 120, 23);

        glyphAComboBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                glyphComboBoxActionPerformed(glyphAComboBox, 0);
            }
        });

        glyphBComboBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                glyphComboBoxActionPerformed(glyphBComboBox, 1);
            }
        });

        glyphCComboBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                glyphComboBoxActionPerformed(glyphCComboBox, 2);
            }
        });

        importLinkButton.setText("Import Link");
        importLinkButton.setToolTipText("Import the link to the right into the talent calculator, this can be in WowHead or Blizzard format");
        importLinkButton.addActionListener(this);
        importLinkButton.setActionCommand("importTalentURL");
        importLinkButton.setBounds(10, 520, 150, 23);

        resetTalentsButton.setText("Reset Talents");
        resetTalentsButton.setToolTipText("Set the talents to zero");
        resetTalentsButton.addActionListener(this);
        resetTalentsButton.setActionCommand("resetTalents");
        resetTalentsButton.setBounds(10, 550, 150, 23);

        exportBlizzardButton.setText("Export Blizzard");
        exportBlizzardButton.setToolTipText("Export the current talent spec in Blizzard format to the clipboard");
        exportBlizzardButton.setBounds(170, 550, 150, 23);
        exportBlizzardButton.addActionListener(this);
        exportBlizzardButton.setActionCommand("exportBlizzardTalentURL");

        exportWowHeadButton.setText("Export WowHead");
        exportWowHeadButton.setToolTipText("Export the current talent spec in WowHead format to the clipboard");
        exportWowHeadButton.setBounds(170, 520, 150, 23);
        exportWowHeadButton.addActionListener(this);
        exportWowHeadButton.setActionCommand("exportWowHeadTalentURL");

        loadTalentsButton.setText("Load Talents");
        loadTalentsButton.setToolTipText("Load a talent set from a XML file");
        loadTalentsButton.setBounds(10, 580, 150, 23);
        loadTalentsButton.addActionListener(this);
        loadTalentsButton.setActionCommand("loadTalents");

        saveTalentsButton.setText("Save Talents");
        saveTalentsButton.setToolTipText("Save a talent set to a XML file");
        saveTalentsButton.setBounds(170, 580, 150, 23);
        saveTalentsButton.addActionListener(this);
        saveTalentsButton.setActionCommand("saveTalents");

        pointsRemaining.setText("Total Remaining");
        pointsRemaining.setBounds(360, 550, 110, 14);

        totalPoints.setText("Total Points");
        totalPoints.setBounds(360, 530, 110, 14);

        glyphsLabel.setText("Glpyhs");
        glyphsLabel.setBounds(515, 525, 110, 14);
        
		System.out.println("Length of talent list " + c_talentList.length);
		m_hashMapTalent = new HashMap<String, CTalent>(c_talentList.length);
		m_talentTreeMap = new HashMap<String, CTalentTree>(3);
        m_talentTree[0] = new CTalentTree("Assassination", 0);
        m_talentTree[1] = new CTalentTree("Combat", 1);
        m_talentTree[2] = new CTalentTree("Subtlety", 2);
        m_talentTreeMap.put("Assassination", m_talentTree[0]);
        m_talentTreeMap.put("Combat", m_talentTree[1]);
        m_talentTreeMap.put("Subtlety", m_talentTree[2]);
        m_maxPoints = 71; // Level 80
		
		for (int i = 0; i < c_talentList.length; i ++)
		{
			CTalent l_talent = getTalentDefault(i);
			String l_talentName = l_talent.getName();
			m_hashMapTalent.put(l_talentName, l_talent);
            m_talentTreeMap.get(l_talent.getTree()).addTalent(l_talent);
            l_talent.setParents(m_talentTreeMap.get(l_talent.getTree()), this);
            for (int j = 1; j < c_toolTips[i].length; j ++)
            {
                l_talent.getToolTip().addRank(c_toolTips[i][j]);
            }
		}

        for (int i = 0; i < c_talentList.length; i++)
        {
            CTalent l_talent = m_hashMapTalent.get(getTalentName(i));
            l_talent.setCurrentPoints(0, false);
        }
	}

    public void actionPerformed(ActionEvent e) {
            String command = e.getActionCommand();
            if(command.equals("importTalentURL")) {
               // import a talent string
               String l_talentString = JOptionPane.showInputDialog("Enter the talent string");
               if (l_talentString != null)
               {
                    boolean l_result = importTalentString(l_talentString);
               }
            }
            else if (command.equals("exportBlizzardTalentURL"))
            {
               // export blizzard talent string to clipboard
                String l_talentString = exportBlizzardTalentString(true);
                CUtility.writeToClipboard(l_talentString);
            }
            else if (command.equals("exportWowHeadTalentURL"))
            {
                // export wow head talent string to clipboard
                String l_talentString = exportWowheadTalentString(true);
                CUtility.writeToClipboard(l_talentString);
            }
            else if (command.equals("loadTalents"))
            {
                this.read();
            }
            else if (command.equals("saveTalents"))
            {
                this.save();
            }
            else if (command.equals("resetTalents"))
            {
                this.resetTalents();
            }

         }

    private void glyphComboBoxActionPerformed(JComboBox p_comboBox, int p_index) {
        this.setGlyph((String) p_comboBox.getSelectedItem(), p_index, false);
        CGlobal.g_rootFrame.setStats();
    }

	// String breaks down to
    // CTalent Name
    // CTalent group 'A', 'C' or 'S'
    // Tier
    // Max Points for CTalent
    // X index into tier (1-4)
    // Option CTalent name that is required for talent to be active
	final String c_talentList[] = 
	{   // Assassination Tree
		"Improved Eviscerate:A:1:3:1", "Remorseless Attacks:A:1:2:2", "Malice:A:1:5:3",
		"Ruthlessness:A:2:3:1",	"Blood Spatter:A:2:2:2", "Puncturing Wounds:A:2:3:4",
		"Vigor:A:3:1:1", "Improved Expose Armor:A:3:2:2", "Lethality:A:3:5:3:Malice",
		"Vile Poisons:A:4:3:2",	"Improved Poisons:A:4:5:3",
		"Fleet Footed:A:5:2:1", "Cold Blood:A:5:1:2", "Improved Kidney Shot:A:5:3:3", "Quick Recovery:A:5:2:4",
		"Seal Fate:A:6:5:2:Cold Blood", "Murder:A:6:2:3",
		"Deadly Brew:A:7:2:1", "Overkill:A:7:1:2", "Deadened Nerves:A:7:3:3",
		"Focused Attacks:A:8:3:1", "Find Weakness:A:8:3:3",
		"Master Poisoner:A:9:3:1", "Mutilate:A:9:1:2:Overkill", "Turn the Tables:A:9:3:3",
		"Cut to the Chase:A:10:5:2",
		"Hunger For Blood:A:11:1:2",
		// Combat Tree [27]
		"Improved Gouge:C:1:3:1", "Improved Sinister Strike:C:1:2:2", "Dual Wield Specialization:C:1:5:3",
		"Improved Slice and Dice:C:2:2:1", "Deflection:C:2:3:2", "Precision:C:2:5:4",
		"Endurance:C:3:2:1", "Riposte:C:3:1:2", "Close Quarters Combat:C:3:5:3:Dual Wield Specialization",
		"Improved Kick:C:4:2:1", "Improved Sprint:C:4:2:2", "Lightning Reflexes:C:4:3:3", "Aggression:C:4:5:4",
		"Mace Specialization:C:5:5:1", "Blade Flurry:C:5:1:2", "Sword Specialization:C:5:5:3",
		"Weapon Expertise:C:6:2:2:Blade Flurry", "Blade Twisting:C:6:2:3",
		"Vitality:C:7:3:1", "Adrenaline Rush:C:7:1:2", "Nerves of Steel:C:7:2:3",
		"Throwing Specialization:C:8:2:1", "Combat Potency:C:8:5:3",
		"Unfair Advantage:C:9:2:1", "Surprise Attacks:C:9:1:2:Adrenaline Rush", "Savage Combat:C:9:2:3",
		"Prey on the Weak:C:10:5:2",
		"Murder Spree:C:11:1:2",
		// Subtlety Tree [55] (Note that the image on the wow website for Dirty Deeds is actually
        // called 'improvedsap.jpg'
		"Relentless Strikes:S:1:5:1", "Master of Deception:S:1:3:2", "Opportunity:S:1:2:3",
		"Sleight of Hand:S:2:2:1", "Dirty Tricks:S:2:2:2", "Camouflage:S:2:3:3",
		"Elusiveness:S:3:2:1", "Ghostly Strike:S:3:1:2", "Serrated Blades:S:3:3:3",
		"Setup:S:4:3:1", "Initiative:S:4:3:2", "Improved Ambush:S:4:2:3",
		"Heightened Senses:S:5:2:1", "Preparation:S:5:1:2", "Dirty Deeds:S:5:2:3", "Hemorrhage:S:5:1:4:Serrated Blades",
		"Master of Subtlety:S:6:3:1", "Deadliness:S:6:5:3",
		"Enveloping Shadows:S:7:3:1", "Premeditation:S:7:1:2:Preparation", "Cheat Death:S:7:3:3",
		"Sinister Calling:S:8:5:2:Premeditation", "Waylay:S:8:2:3",
		"Honor Among Thieves:S:9:3:1", "Shadow Step:S:9:1:2", "Filthy Tricks:S:9:2:3",
		"Slaughter from the Shadows:S:10:5:2",
		"Shadow Dance:S:11:1:2"
	};

    public boolean importTalentString(String p_talentString)
    {
        if (p_talentString == null || p_talentString.equals(""))
        {
            p_talentString = "00000000000000000000000000000000000000000000000000000000000000000000000000000000000";
        }
        
        if (p_talentString.substring(0,4).equals("http"))
        {
            // URL incomming
            // Is it blizzard or wowhead ?
            if (p_talentString.substring(0,23).equals("http://www.wowhead.com/"))
            {
                // Could be wowhead, proper Rogue string ?
                if (p_talentString.substring(0,32).equals("http://www.wowhead.com/?talent=f"))
                {
                    // proper rogue start string
                    String l_wowheadTalentString = p_talentString.substring(32, p_talentString.length());
                    return importWowheadTalentString(l_wowheadTalentString);
                }

                System.out.println("Weird wowhead talent string!!");
                return false;
            }
            else
            {
                StringTokenizer st = new StringTokenizer(p_talentString, "=");
                String l_dummy = st.nextToken();
                if (l_dummy == null)
                {
                    System.out.println("Weird blizzard talent string!!");
                    return false;
                }
                String l_blizzardTalentString = st.nextToken();
                if (l_blizzardTalentString == null)
                {
                    System.out.println("Weird blizzard talent string!!");
                    return false;
                }

                return importBlizzardTalentString(l_blizzardTalentString);
            }
        }

        // Gonna assume this is direct from armory
        return importBlizzardTalentString(p_talentString);
    }

	public boolean importBlizzardTalentString(String p_talentString)
	{
        resetTalents();

        System.out.println("Importing string [" + p_talentString + "]");
        
		for (int i = 0; i < c_talentList.length; i++)
		{
			int l_talentPoints = Integer.parseInt(p_talentString.substring(i,i + 1));
			
			CTalent l_talent = (CTalent) m_hashMapTalent.get(getTalentName(i));
			l_talent.setCurrentPoints(l_talentPoints, false);
		}
		return true;
	}

	public String exportBlizzardTalentString(boolean p_withURL)
	{

        String l_talentString = "";
        if (p_withURL)
        {
            l_talentString += "http://www.wow-europe.com/en/info/basics/talents/rogue/talents.html?tal=";
        }

		for (int i = 0; i < c_talentList.length; i++)
		{
            l_talentString += m_hashMapTalent.get(getTalentName(i)).getCurrentPoints();
		}

		return l_talentString;
	}

	public String exportWowheadTalentString(boolean p_withURL)
	{
        HashMap<String, String> l_hashMap = new HashMap<String, String>()
        {{
            put("00", "0"); put("01", "z"); put("02", "M"); put("03","c"); put("04","m"); put("05", "V");
            put("10", "o"); put("11", "k"); put("12", "R"); put("13","s"); put("14","a"); put("15", "q");
            put("20", "b"); put("21", "d"); put("22", "r"); put("23","f"); put("24","w"); put("25", "i");
            put("30", "h"); put("31", "u"); put("32", "G"); put("33","I"); put("34","N"); put("35", "A");
            put("40", "L"); put("41", "p"); put("42", "T"); put("43","j"); put("44","n"); put("45", "y");
            put("50", "x"); put("51", "t"); put("52", "g"); put("53","e"); put("54","v"); put("55", "E");
        }};

        String l_talentString = "";
        if (p_withURL)
        {
            l_talentString += "http://www.wowhead.com/?talent=f";
        }

        // Search all talent trees
        for (int i = 0; i < 3; i++)
        {
            int l_lastTalent;

            l_lastTalent = -1;
            CTalentTree l_talentTree = getTalentTree(i);
            // Work out where the last set talent is in the tree
            for (int j = 0; j < l_talentTree.getMaxTalents(); j++)
            {
                if (l_talentTree.getTalent(j).getCurrentPoints() > 0)
                {
                    l_lastTalent = j;
                }
            }

            if (l_lastTalent == -1)
            {
                // Skip tree
                l_talentString += "Z";
            }
            else
            {
                String l_twoTalents = "";
                int j = 0;
                for (j = 0; j <= l_lastTalent;)
                {
                    l_twoTalents = String.valueOf(l_talentTree.getTalent(j++).getCurrentPoints());
                    if (j < l_talentTree.getMaxTalents())
                    {
                        l_twoTalents += String.valueOf(l_talentTree.getTalent(j++).getCurrentPoints());
                    }
                    else
                    {
                        l_twoTalents += "0";
                    }

                    l_talentString += l_hashMap.get(l_twoTalents);
                }

                // Need a seperator if last talent in the tree was used and not
                // the last talent tree
                if (j < l_talentTree.getMaxTalents() && i != 2)
                {
                    l_talentString += "Z";
                }
            }
        }

		return l_talentString;
	}

	public boolean importWowheadTalentString(String p_talentString)
	{
        String l_decoder[][] =
        {{ "0", "0", "0" },  { "z", "0", "1" },  { "M", "0", "2" },  { "c", "0", "3" }, { "m", "0", "4" },  { "V", "0", "5" },
            { "o", "1", "0" },  { "k", "1", "1" },  { "R", "1", "2" },  { "s", "1", "3" }, { "a", "1", "4" },  { "q", "1", "5" },
            { "b", "2", "0" },  { "d", "2", "1" },  { "r", "2", "2" },  { "f", "2", "3" }, { "w", "2", "4" },  { "i", "2", "5" },
            { "h", "3", "0" },  { "u", "3", "1" },  { "G", "3", "2" },  { "I", "3", "3" }, { "N", "3", "4" },  { "A", "3", "5" },
            { "L", "4", "0" },  { "p", "4", "1" },  { "T", "4", "2" },  { "j", "4", "3" }, { "n", "4", "4" },  { "y", "4", "5" },
            { "x", "5", "0" },  { "t", "5", "1" },  { "g", "5", "2" },  { "e", "5", "3" }, { "v", "5", "4" },  { "E", "5", "5" }
            };

        System.out.println("Importing wow talent string [" + p_talentString + "]");
        resetTalents();
        int l_stringIndex = 0;
        int l_stringLength = p_talentString.length();
        String l_currentChar="";

		for (int i = 0; i < 3; i++)
		{
            CTalentTree l_talentTree = getTalentTree(i);
            System.out.println("Tree " + i);

            for (int j = 0; j < l_talentTree.getMaxTalents();)
            {
                if (l_stringIndex == l_stringLength)
                {
                    return true;
                }

                l_currentChar = p_talentString.substring(l_stringIndex,l_stringIndex + 1);
                if (l_currentChar.equals("Z"))
                {
                    l_stringIndex++;
                    break;
                }

                boolean l_foundMatch = false;
                for (int k = 0; k < l_decoder.length; k++)
                {
                    if (l_decoder[k][0].equals(l_currentChar))
                    {
                        System.out.println("Found match");
                        
                        l_talentTree.getTalent(j).setCurrentPoints(Integer.parseInt(l_decoder[k][1]), false);
                        System.out.println("Set talent " + l_talentTree.getTalent(j).getName() + " to " + l_talentTree.getTalent(j).getCurrentPoints());
                        j++;

                        if (j <l_talentTree.getMaxTalents())
                        {
                            l_talentTree.getTalent(j).setCurrentPoints(Integer.parseInt(l_decoder[k][2]), false);
                            System.out.println("Set talent " + l_talentTree.getTalent(j).getName() + " to " + l_talentTree.getTalent(j).getCurrentPoints());
                            j++;
                        }

                        l_stringIndex++;
                        l_foundMatch = true;
                        break;
                    }
                }

                if (!l_foundMatch)
                {
                    return false;
                }
            }
		}
		return true;
	}

    public void resetTalents()
    {
		for (int i = 0; i < 3; i++)
		{
            CTalentTree l_talentTree = getTalentTree(i);
            l_talentTree.resetTreePoints();
		}
    }

    public void assignLabelsToTalents(JLayeredPane p_parentComponent)
    {
		for (int i = 0; i < c_talentList.length; i++)
		{
			CTalent l_talent = (CTalent) m_hashMapTalent.get(getTalentName(i));
            // System.out.println("Setting icons for talent " + l_talent.getName());
            p_parentComponent.add(l_talent.getIcon(), javax.swing.JLayeredPane.PALETTE_LAYER);
            p_parentComponent.add(l_talent.getText(), javax.swing.JLayeredPane.MODAL_LAYER);
		}

        for (int i = 0; i < 3; i++)
        {
            p_parentComponent.add(getTalentTree(i).getIcon(), javax.swing.JLayeredPane.DEFAULT_LAYER);
            p_parentComponent.add(getTalentTree(i).getText(), javax.swing.JLayeredPane.PALETTE_LAYER);
        }

        p_parentComponent.add(importLinkButton, javax.swing.JLayeredPane.DEFAULT_LAYER);
        p_parentComponent.add(exportBlizzardButton, javax.swing.JLayeredPane.DEFAULT_LAYER);
        p_parentComponent.add(exportWowHeadButton, javax.swing.JLayeredPane.DEFAULT_LAYER);
        p_parentComponent.add(pointsRemaining, javax.swing.JLayeredPane.DEFAULT_LAYER);
        p_parentComponent.add(totalPoints, javax.swing.JLayeredPane.DEFAULT_LAYER);
        p_parentComponent.add(glyphsLabel, javax.swing.JLayeredPane.DEFAULT_LAYER);
        p_parentComponent.add(loadTalentsButton, javax.swing.JLayeredPane.DEFAULT_LAYER);
        p_parentComponent.add(saveTalentsButton, javax.swing.JLayeredPane.DEFAULT_LAYER);
        p_parentComponent.add(resetTalentsButton, javax.swing.JLayeredPane.DEFAULT_LAYER);
        p_parentComponent.add(this.glyphAComboBox, javax.swing.JLayeredPane.DEFAULT_LAYER);
        p_parentComponent.add(this.glyphBComboBox, javax.swing.JLayeredPane.DEFAULT_LAYER);
        p_parentComponent.add(this.glyphCComboBox, javax.swing.JLayeredPane.DEFAULT_LAYER);
    }

	public CTalent getTalent(String p_talentName)
	{
		return m_hashMapTalent.get(p_talentName);
	}

    public int getTotalPoints()
    {
        return m_talentTree[0].getTotalPoints() + m_talentTree[1].getTotalPoints() + m_talentTree[2].getTotalPoints();
    }

	private CTalent getTalentDefault(int p_index)
	{
		StringTokenizer st = new StringTokenizer(c_talentList[p_index], ":");
		String l_talentName = st.nextToken();
		String l_treeCode = st.nextToken();
		String l_treeName = "";
		if (l_treeCode.equals("A"))
		{
			l_treeName = "Assassination";
			
		} 
		else if (l_treeCode.equals("C"))
		{
			l_treeName = "Combat";
		}
		else
		{
			l_treeName = "Subtlety";	
		}
		
		int l_tier  = Integer.parseInt(st.nextToken());
		int l_maxPoints = Integer.parseInt(st.nextToken());
        int l_xIndex = Integer.parseInt(st.nextToken());
        String l_dependency = null;
        if (st.hasMoreElements())
        {
            l_dependency = st.nextToken();
        }
		// System.out.println("Talent [" + l_talentName + "] Max Points [" + l_maxPoints + "]");
		return (new CTalent(l_talentName, l_treeName, l_tier, l_maxPoints, l_xIndex, l_dependency));
	}
	
	private String getTalentName(int p_index)
	{
		StringTokenizer st = new StringTokenizer(c_talentList[p_index], ":");
		return (st.nextToken());
	}

    public int  getMaxPoints()
    {
        return m_maxPoints;
    }

    public HashMap<String, CTalent> getTalentHashMap()
    {
        return m_hashMapTalent;
    }

    public CTalentTree getTalentTree(int p_index)
    {
        return m_talentTree[p_index];
    }

    public void updateTextTotals()
    {
        pointsRemaining.setText("Total Remaining: " + (this.getMaxPoints() - this.getTotalPoints()));
        totalPoints.setText("Total Points: " + this.getTotalPoints());
    }

    public void clearGlyphs()
    {
        this.m_glyphs.clear();
        this.m_glyphs.add("None");
        this.m_glyphs.add("None");
        this.m_glyphs.add("None");
        this.glyphAComboBox.setSelectedItem("None");
        this.glyphBComboBox.setSelectedItem("None");
        this.glyphCComboBox.setSelectedItem("None");
    }

    public void setGlyph(String p_glyph, int p_index, boolean p_updateComboBox)
    {
        if (p_index == 0)
        {
            this.m_glyphs.set(p_index, p_glyph);
            if (p_updateComboBox)
            {
                glyphAComboBox.setSelectedItem(p_glyph);
            }
        } else if (p_index == 1)
        {
            this.m_glyphs.set(p_index, p_glyph);
            if (p_updateComboBox)
            {
                glyphBComboBox.setSelectedItem(p_glyph);
            }
        } else if (p_index == 2)
        {
            this.m_glyphs.set(p_index, p_glyph);
            if (p_updateComboBox)
            {
                glyphCComboBox.setSelectedItem(p_glyph);
            }
        }
    }

    public boolean isGlyphSet(String p_glyph)
    {
        for (int i = 0; i < 3; i++)
        {
            if (m_glyphs.get(i).equals(p_glyph))
            {
                return true;
            }
        }

        return false;
    }
    
    public void save()
    {
        String l_string = CUtility.openXMLFileSaveDialog("talents", "Set a filename for this talent build");
        if (l_string == null)
        {
            return;
        }

        this.save(l_string);
    }

    public void save(String p_fileName) {
        Document doc = DocumentFactory.getInstance().createDocument();
        Element root = doc.addElement("root");
        this.addXMLData(root);

        if (!p_fileName.endsWith(".xml"))
        {
            p_fileName = p_fileName + ".xml";
        }

        FileOutputStream fos;
        try {
            fos = new FileOutputStream(p_fileName);
            OutputFormat format = OutputFormat.createPrettyPrint();
            XMLWriter writer;
            try {
                writer = new XMLWriter(fos, format);
                try {
                    writer.write(doc);
                    writer.flush();
                    writer.close();
                } catch (IOException ex) {
                    Logger.getLogger(CDatabase.class.getName()).log(Level.SEVERE, null, ex);
                }

            } catch (UnsupportedEncodingException ex) {
                Logger.getLogger(CDatabase.class.getName()).log(Level.SEVERE, null, ex);
            }

        } catch (FileNotFoundException ex) {
            Logger.getLogger(CDatabase.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void addXMLData(Element p_root)
    {
        String l_talentString = this.exportBlizzardTalentString(false);
        p_root.addElement("talents").addAttribute("talentstring", l_talentString).
                addAttribute("glypha", this.glyphAComboBox.getSelectedItem().toString()).
                addAttribute("glyphb", this.glyphBComboBox.getSelectedItem().toString()).
                addAttribute("glyphc", this.glyphCComboBox.getSelectedItem().toString());
    }

    public void read()
    {
        String l_string = CUtility.openXMLFileOpenDialog("talents", "Choose a Talent build data file");
        if (l_string == null)
        {
            return;
        }

        this.read(l_string);
    }

    public void read(String l_fileName)
    {
        System.out.println("File String " + l_fileName);

        File l_xml = new File(l_fileName);
        SAXReader l_reader = new SAXReader();
        Document l_doc;
        try {
            l_doc = l_reader.read(l_xml);
            Element l_element = (Element) l_doc.selectSingleNode( "//root/talents" );
            this.parseXMLElement(l_element);
        } catch (DocumentException ex) {
            Logger.getLogger(CPaperDoll.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void parseXMLElement(Element p_element)
    {
        String l_value = p_element.attributeValue("talentstring");
        this.importTalentString(l_value);
        this.setGlyph(p_element.attributeValue("glypha"), 0, true);
        this.setGlyph(p_element.attributeValue("glyphb"), 1, true);
        this.setGlyph(p_element.attributeValue("glyphc"), 2, true);
    }

final String[][] c_toolTips = {
//Assassination Talents Begin

//Improved Eviscerate - Assassination
{"Improved Eviscerate",
"Increases the damage done by your Eviscerate ability by 7%.",
"Increases the damage done by your Eviscerate ability by 14%.",
"Increases the damage done by your Eviscerate ability by 20%."
},

//Remorseless Attacks - Assassination
{"Remorseless Attacks",
"After killing an opponent that yields experience or<BR>honor, gives you a 20% increased critical strike<BR>chance on your next Sinister Strike, Backstab,<BR>Mutilate, Hemorrhage, Ambush, or Ghostly Strike.<BR>Lasts 20 sec.",
"After killing an opponent that yields experience or<BR>honor, gives you a 40% increased critical strike<BR>chance on your next Sinister Strike, Backstab,<BR>Mutilate, Hemorrhage, Ambush, or Ghostly Strike.<BR>Lasts 20 sec."
},
//Malice - Assassination

{"Malice",
"Increases your critical strike chance by 1%.",
"Increases your critical strike chance by 2%.",
"Increases your critical strike chance by 3%.",
"Increases your critical strike chance by 4%.",
"Increases your critical strike chance by 5%."
},
//Ruthlessness - Assassination

{"Ruthlessness",
"Gives your melee finishing moves a 20% chance<BR>to add a combo point to your target.",
"Gives your melee finishing moves a 40% chance<BR>to add a combo point to your target.",
"Gives your melee finishing moves a 60% chance<BR>to add a combo point to your target."
},

//Blood Spatter - Assassination
{"Blood Spatter",
"Increases the damage caused by your Garrote<BR>and Rupture abilities by 15%.",
"Increases the damage caused by your Garrote<BR>and Rupture abilities by 30%."
},


//Puncturing Wounds - Assassination
{"Puncturing Wounds",
"Increases the critical strike chance of your<BR>Backstab ability by 10%, and the critical strike<BR>chance of your Mutilate ability by 5%.",
"Increases the critical strike chance of your<BR>Backstab ability by 20%, and the critical strike<BR>chance of your Mutilate ability by 10%.",
"Increases the critical strike chance of your<BR>Backstab ability by 30%, and the critical strike<BR>chance of your Mutilate ability by 15%."
},

//Vigor - Assassination
{
"Vigor",
"Increases your maximum Energy by 10."
},


//Improved Expose Armor - Assassination
{"Improved Expose Armor" ,
"Reduces the energy cost of your Expose Armor ability by 5.",
"Reduces the energy cost of your Expose Armor ability by 10."
},

//Lethality - Assassination
{"Lethality",
"Increases the critical strike damage bonus<BR>of all combo point-generating abilities that <BR>do not require stealth by 6%.",
"Increases the critical strike damage bonus<BR>of all combo point-generating abilities that <BR>do not require stealth by 12%.",
"Increases the critical strike damage bonus<BR>of all combo point-generating abilities that <BR>do not require stealth by 18%.",
"Increases the critical strike damage bonus<BR>of all combo point-generating abilities that <BR>do not require stealth by 24%.",
"Increases the critical strike damage bonus<BR>of all combo point-generating abilities that <BR>do not require stealth by 30%.",
},

//Vile Poisons - Assassination
{"Vile Poisons",
"Increases the damage dealt by your poisons and<BR>Envenom ability by 7% and gives your damage over time poisons<BR>an additional 10% chance to resist dispel effects.",
"Increases the damage dealt by your poisons and<BR>Envenom ability by 14% and gives your damage over time poisons<BR>an additional 20% chance to resist dispel effects.",
"Increases the damage dealt by your poisons and<BR>Envenom ability by 20% and gives your damage over time poisons<BR>an additional 30% chance to resist dispel effects."
},

//Improved Poisons - Assassination
{"Improved Poisons",
"Increases the chance to apply Deadly Poison<BR> to your target by 2% and the frequency of<BR>applying Instant Poison to your <BR>target by 10%.",
"Increases the chance to apply Deadly Poison<BR> to your target by 4% and the frequency of<BR>applying Instant Poison to your <BR>target by 20%.",
"Increases the chance to apply Deadly Poison<BR> to your target by 6% and the frequency of<BR>applying Instant Poison to your <BR>target by 30%.",
"Increases the chance to apply Deadly Poison<BR> to your target by 8% and the frequency of<BR>applying Instant Poison to your <BR>target by 40%.",
"Increases the chance to apply Deadly Poison<BR> to your target by 10% and the frequency of<BR>applying Instant Poison to your <BR>target by 50%."
},

//Fleet Footed - Assassination
{"Fleet Footed",
"Reduces the duration of all movement impairing<BR>effects by 15% and increases your movement<BR>speed by 8% This does not stack with<BR>other movement speed increasing effects.",
"Reduces the duration of all movement impairing<BR>effects by 30% and increases your movement<BR>speed by 15% This does not stack with<BR>other movement speed increasing effects."
},

//Cold Blood - Assassination
{"Cold Blood",
"<span style=text-align:left;float:left;>Instant</span><span style=text-align:right;float:right;>3 min cooldown</span><br>When activated, increases the critical strike chance of your next offensive ability by 100%."
},

//Improved Kidney Shot - Assassination
{"Improved Kidney Shot",
"While affected by your Kidney Shot ability,<BR>target receives an additional 3% damage<BR>from all sources.",
"While affected by your Kidney Shot ability,<BR>target receives an additional 6% damage<BR>from all sources.",
"While affected by your Kidney Shot ability,<BR>target receives an additional 9% damage<BR>from all sources."
},

//Quick Recovery - Assassination
{"Quick Recovery",
"All healing effects on you are increased by 10%.<BR>In addition, your finishing moves cost 40%<BR>less Energy when they fail to hit.",
"All healing effects on you are increased by 20%.<BR>In addition, your finishing moves cost 80%<BR>less Energy when they fail to hit."
},

//Seal Fate - Assassination
{"Seal Fate",
"Your critical strikes from abilities that add<BR>combo points have a 20% chance to add<BR>an additional combo point.",
"Your critical strikes from abilities that add<BR>combo points have a 40% chance to add<BR>an additional combo point.",
"Your critical strikes from abilities that add<BR>combo points have a 60% chance to add<BR>an additional combo point.",
"Your critical strikes from abilities that add<BR>combo points have a 80% chance to add<BR>an additional combo point.",
"Your critical strikes from abilities that add<BR>combo points have a 100% chance to add<BR>an additional combo point."
},

//Murder - Assassination
{"Murder",
"Increases all damage caused against Humanoid, Giant,<BR>Beast, and Dragonkin targets by 2%",
"Increases all damage caused against Humanoid, Giant,<BR>Beast, and Dragonkin targets by 4%"
},

//Deadly Brew - Assassination
{"Deadly Brew",
"When you apply Instant, Wounding or Mind-Numbing<BR>poison to a target, you have a 50% chance<BR>to apply Crippling poison.",
"When you apply Instant, Wounding or Mind-Numbing<BR>poison to a target, you have a 100% chance<BR>to apply Crippling poison."
},

//Overkill - Assassination
{"Overkill",
"Abilities used while stealthed and for 6 seconds after<BR>breaking stealth cost 10 less energy.",
},

//Deadened Nerves - Assassination
{"Deadened Nerves",
"Decreases all damage taken by 2%.",
"Decreases all damage taken by 4%.",
"Decreases all damage taken by 6%."
},

//Focused Attacks - Assassination
{"Focused Attacks",
"Your melee critical strikes have a<BR>33% chance to give you 2 energy.",
"Your melee critical strikes have a<BR>66% chance to give you 2 energy.",
"Your melee critical strikes have a<BR>100% chance to give you 2 energy."
},

//Find Weakness - Assassination
{"Find Weakness",
"Offensive ability damage increased by 2%.",
"Offensive ability damage increased by 4%.",
"Offensive ability damage increased by 6%."
},

//Master Poisoner - Assassination
{"Master Poisoner",
"Increases the critical hit chance of all attacks<BR>made against any target you have poisoned by 1%<BR>,reduces the duration of all Poison effects<BR>applied to you by 17% and increases the bonus<BR>chance to apply Deadly Poison when Envenom is used<BR>by an addition 15%.",
"Increases the critical hit chance of all attacks<BR>made against any target you have poisoned by 2%<BR>,reduces the duration of all Poison effects<BR>applied to you by 34% and increases the bonus<BR>chance to apply Deadly Poison when Envenom is used<BR>by an addition 30%.",
"Increases the critical hit chance of all attacks<BR>made against any target you have poisoned by 3%<BR>,reduces the duration of all Poison effects<BR>applied to you by 50% and increases the bonus<BR>chance to apply Deadly Poison when Envenom is used<BR>by an addition 45%.",
},

//Mutilate - Assassination
{"Mutilate",
"<span style=text-align:left;float:left;>60 Energy</span><span style=text-align:right;float:right;>Melee range</span>" +
         "<br>Instant<br>Requires Daggers<br>Instantly attacks with both weapons for an additional 181 with each weapon." +
         "<BR>Damage is increased by 20% against Poisoned targets.<BR>Awards 2 combo points.<br><br>" +
"&nbsp;Talent has trainable ranks<br>"
},

//Turn the Tables - Assassination
{"Turn the Tables",
"Whenever anyone in your party or raid blocks, dodges,<BR>or parries an attack your chance to critically hit<BR>with all combo moves is increased by 2% for 8 sec.",
"Whenever anyone in your party or raid blocks, dodges,<BR>or parries an attack your chance to critically hit<BR>with all combo moves is increased by 4% for 8 sec.",
"Whenever anyone in your party or raid blocks, dodges,<BR>or parries an attack your chance to critically hit<BR>with all combo moves is increased by 6% for 8 sec."
},

//Cut to the Chase - Assassination
{"Cut to the Chase",
"Your Eviscerate and Envenom abilities have<BR>a 20% chance to refresh your Slice and Dice duration<BR>to its 5 combo point maximum.",
"Your Eviscerate and Envenom abilities have<BR>a 40% chance to refresh your Slice and Dice duration<BR>to its 5 combo point maximum.",
"Your Eviscerate and Envenom abilities have<BR>a 60% chance to refresh your Slice and Dice duration<BR>to its 5 combo point maximum.",
"Your Eviscerate and Envenom abilities have<BR>a 80% chance to refresh your Slice and Dice duration<BR>to its 5 combo point maximum.",
"Your Eviscerate and Envenom abilities have<BR>a 100% chance to refresh your Slice and Dice duration<BR>to its 5 combo point maximum."
},

//Hunger For Blood - Assassination
{"Hunger For Blood",
"<span style=text-align:left;float:left;>30 Energy</span><br><span style=text-align:left;float:left;>Instant</span><br>" +
"Enrages you, increasing all damage caused by 15%.<BR>Requires a bleed effect to be active on the target<BR>Lasts 1 min."
},

//COMBAT TREE------------------------------------------------------------------------------
//Improved Gouge - Combat
{"Improved Gouge",
"Increases the effect duration of your Gouge<BR>ability by 0.5 sec.",
"Increases the effect duration of your Gouge<BR>ability by 1 sec.",
"Increases the effect duration of your Gouge<BR>ability by 1.5 sec."
},

//Improved Sinister Strike - Combat
{"Improved Sinister Strike",
"Reduces the Energy cost of your Sinister Strike ability by 3.",
"Reduces the Energy cost of your Sinister Strike ability by 5."
},

//Dual Wield Specialization - Combat
{"Dual Wield Specialization",
"Increases the damage done by your offhand weapon by 10%.",
"Increases the damage done by your offhand weapon by 20%.",
"Increases the damage done by your offhand weapon by 30%.",
"Increases the damage done by your offhand weapon by 40%.",
"Increases the damage done by your offhand weapon by 50%."
},

//Improved Slice and Dice - Combat
{"Improved Slice and Dice",
"Increases the duration of your Slice and Dice ability by 25%.",
"Increases the duration of your Slice and Dice ability by 50%."
},

//Deflection - Combat
{"Deflection",
"Increases your Parry chance by 2%.",
"Increases your Parry chance by 4%.",
"Increases your Parry chance by 6%."
},

//Precision - Combat
{"Precision",
"Increases your chance to hit with weapon<BR>and poison attacks by 1%.",
"Increases your chance to hit with weapon<BR>and poison attacks by 2%.",
"Increases your chance to hit with weapon<BR>and poison attacks by 3%.",
"Increases your chance to hit with weapon<BR>and poison attacks by 4%.",
"Increases your chance to hit with weapon<BR>and poison attacks by 5%."
},

//Endurance - Combat
{"Endurance",
"Reduces the cooldown of your Sprint and Evasion<BR>abilities by 30 sec and increases your<BR>total Stamina by 2%.",
"Reduces the cooldown of your Sprint and Evasion<BR>abilities by 60 sec and increases your<BR>total Stamina by 4%."
},

//Riposte - Combat
{"Riposte",
"<span style=text-align:left;float:left;>10 Energy</span><span style=text-align:right;float:right;>Melee range</span><br><span style=text-align:left;float:left;>Instant</span><span style=text-align:right;float:right;>6 sec cooldown</span><br>A strike that becomes active after parrying an opponent's attack.<BR>This attack deals 150% weapon damage and slows their melee<BR>attack speed by 20% for 30 sec."
},

//Close Quarters Combat - Combat
{"Close Quarters Combat",
"Increases your chance to get a critical strike<BR>with Daggers and Fist Weapons by 1%.",
"Increases your chance to get a critical strike<BR>with Daggers and Fist Weapons by 2%.",
"Increases your chance to get a critical strike<BR>with Daggers and Fist Weapons by 3%.",
"Increases your chance to get a critical strike<BR>with Daggers and Fist Weapons by 4%.",
"Increases your chance to get a critical strike<BR>with Daggers and Fist Weapons by 5%."
},

//Improved Kick - Combat
{"Improved Kick",
"Gives your Kick ability a 50% chance to silence<BR>the target for 2 sec.",
"Gives your Kick ability a 100% chance to silence<BR>the target for 2 sec."
},

//Improved Sprint - Combat
{"Improved Sprint",
"Gives a 50% chance to remove all movement imparing<BR>effects when you activate your Sprint ability.",
"Gives a 100% chance to remove all movement imparing<BR>effects when you activate your Sprint ability."
},

//Lightning Reflexes - Combat
{"Lightning Reflexes",
"Increases your Dodge chance by 2% and gives you 4% melee haste.",
"Increases your Dodge chance by 4% and gives you 7% melee haste.",
"Increases your Dodge chance by 6% and gives you 10% melee haste.",
},

//Aggression - Combat
{"Aggression",
"Increases the damage of your Sinister Strike,<BR>Backstab, and Eviscerate abilities by 3%.",
"Increases the damage of your Sinister Strike,<BR>Backstab, and Eviscerate abilities by 6%.",
"Increases the damage of your Sinister Strike,<BR>Backstab, and Eviscerate abilities by 9%.",
"Increases the damage of your Sinister Strike,<BR>Backstab, and Eviscerate abilities by 12%.",
"Increases the damage of your Sinister Strike,<BR>Backstab, and Eviscerate abilities by 15%."
},

//Mace Specialization - Combat
{"Mace Specialization",
"Your attacks with maces ignore up to 3% of<BR>your opponents armor.",
"Your attacks with maces ignore up to 6% of<BR>your opponents armor.",
"Your attacks with maces ignore up to 9% of<BR>your opponents armor.",
"Your attacks with maces ignore up to 12% of<BR>your opponents armor.",
"Your attacks with maces ignore up to 15% of<BR>your opponents armor.",
},

//Blade Flurry - Combat
{"Blade Flurry",
"25 Energy<br><span style=text-align:left;float:left;>Instant</span><span style=text-align:right;float:right;>2 min cooldown</span><br>Increases your attack speed by 20%.<BR>In addition, attacks strike an additional nearby opponent.<BR>Lasts 15 sec."
},

//Sword Specialization - Combat
{"Sword Specialization",
"Gives you a 1% chance to get an extra attack<BR>on the same target after hitting your<BR>target with your Sword.",
"Gives you a 2% chance to get an extra attack<BR>on the same target after hitting your<BR>target with your Sword.",
"Gives you a 3% chance to get an extra attack<BR>on the same target after hitting your<BR>target with your Sword.",
"Gives you a 4% chance to get an extra attack<BR>on the same target after hitting your<BR>target with your Sword.",
"Gives you a 5% chance to get an extra attack<BR>on the same target after hitting your<BR>target with your Sword."
},

//Weapon Expertise - Combat
{"Weapon Expertise",
"Increases your expertise by 5.",
"Increases your expertise by 10."
},

//Blade Twisting - Combat
{"Blade Twisting",
"Increases the damage dealt by Sinister Strike and Backstab<BR>by 5% and your damaging melee attacks have a 10% chance<BR>to Daze the target for 4 sec.",
"Increases the damage dealt by Sinister Strike and Backstab<BR>by 10% and your damaging melee attacks have a 10% chance<BR>to Daze the target for 8 sec."
},

//Vitality - Combat
{"Vitality",
"Increases your Energy regeneration rate by 8%.",
"Increases your Energy regeneration rate by 16%.",
"Increases your Energy regeneration rate by 25%."
},

//Adrenaline Rush - Combat
{"Adrenaline Rush",
"<span style=text-align:left;float:left;>Instant</span><span style=text-align:right;float:right;><BR>3 min cooldown</span><br>Increases your Energy regeneration rate by 100% for 15 sec."
},

//Nerves of Steel - Combat
{"Nerves of Steel",
"Reduces the damage taken while affected by Stun<BR>and Fear effects by 15%.",
"Reduces the damage taken while affected by Stun<BR>and Fear effects by 30%."
},

//Throwing Specialization - Combat
{"Throwing Specialization",
"Increases the range of Throw and Deadly Throw by 2 yards<BR>and gives your Deadly Throw abilitie<BR>a 50% chance to interrupt the target for 3 sec.",
"Increases the range of Throw and Deadly Throw by 4 yards<BR>and gives your Deadly Throw abilitie<BR>a 100% chance to interrupt the target for 3 sec."
},

//Combat Potency - Combat
{"Combat Potency",
"Gives your successful off-hand melee autoattacks<BR>a 20% chance to generate 3 Energy.",
"Gives your successful off-hand melee autoattacks<BR>a 20% chance to generate 6 Energy.",
"Gives your successful off-hand melee autoattacks<BR>a 20% chance to generate 9 Energy.",
"Gives your successful off-hand melee autoattacks<BR>a 20% chance to generate 12 Energy.",
"Gives your successful off-hand melee autoattacks<BR>a 20% chance to generate 15 Energy."
},

//Unfair Advantage - Combat
{"Unfair Advantage",
"Whenever you dodge an attack you gain an Unfair Advantage,<BR>striking back for 50% of your main hand weapon's damage.<BR>This cannot occur more than once per second.",
"Whenever you dodge an attack you gain an Unfair Advantage,<BR>striking back for 100% of your main hand weapon's damage.<BR>This cannot occur more than once per second."
},

//Surprise Attacks - Combat
{"Surprise Attacks",
"Your finishing moves can no longer be dodged,<BR>and the damage dealt by your Sinister Strike,<BR>Backstab, Shiv, Hemorrhage and Gouge abilities is<BR>increased by 10%."
},

//Savage Combat - Combat
{"Savage Combat",
"Increases your total attack power by 2% and<BR>all physical damage caused to enemies you have<BR>poisoned is increased by 2%.",
"Increases your total attack power by 4% and<BR>all physical damage caused to enemies you have<BR>poisoned is increased by 4%."
},


//Prey on the Weak - Combat
{"Prey on the Weak",
"Your critical strike damage is increased by 4% when<BR>the target has less health than you (as a percentage<BR>of total health).",
"Your critical strike damage is increased by 8% when<BR>the target has less health than you (as a percentage<BR>of total health).",
"Your critical strike damage is increased by 12% when<BR>the target has less health than you (as a percentage<BR>of total health).",
"Your critical strike damage is increased by 16% when<BR>the target has less health than you (as a percentage<BR>of total health).",
"Your critical strike damage is increased by 20% when<BR>the target has less health than you (as a percentage<BR>of total health)."
},

//Murder Spree - Combat
{"Murder Spree",
"<span style=text-align:left;float:left;>Instant</span><span style=text-align:right;float:right;>2 min cooldown</span><br>Step through the shadows from enemy to enemy<BR>" +
         "within 10 yards, attacking an enemy every 0.5 secs<BR>" +
         "with both weapons until 5 assaults are made and increasing<BR>" +
         "all damage done by 20% for the duration." +
"<BR>Can hit the same target multiple times.<BR>Cannot hit invisible or stealthed targets."
},

//SUBTLETY------------------------------------------------------------------------------------->

//Relentless Strikes - Subtlety
{"Relentless Strikes",
"Your finishing moves have a 4% chance per<BR>combo point to restore 25 energy.",
"Your finishing moves have a 8% chance per<BR>combo point to restore 25 energy.",
"Your finishing moves have a 12% chance per<BR>combo point to restore 25 energy.",
"Your finishing moves have a 16% chance per<BR>combo point to restore 25 energy.",
"Your finishing moves have a 20% chance per<BR>combo point to restore 25 energy."
},

//Master of Deception - Subtlety
{"Master of Deception",
"Reduces the chance enemies have to detect you<BR>while in Stealth mode.",
"Reduces the chance enemies have to detect you<BR>while in Stealth mode.<BR>More effective than Master of Deception (Rank 1).",
"Reduces the chance enemies have to detect you<BR>while in Stealth mode.<BR>More effective than Master of Deception (Rank 2)."
},

//Opportunity - Subtlety
{"Opportunity",
"Increases the damage dealt when striking from behind<BR>with your Backstab, Mutilate, Garrote, and Ambush<BR>abilities by 10%.",
"Increases the damage dealt when striking from behind<BR>with your Backstab, Mutilate, Garrote, and Ambush<BR>abilities by 20%."
},

//Sleight of Hand - Subtlety
{"Sleight of Hand",
"Reduces the chance you are critically hit by melee<BR>and ranged attacks by 1% and increases the threat reduction<BR>of your Feint ability by 10%.",
"Reduces the chance you are critically hit by melee<BR>and ranged attacks by 2% and increases the threat reduction<BR>of your Feint ability by 20%."
},

//Dirty Tricks - Subtlety
{"Dirty Tricks",
"Increases the range of your Blind and Sap abilities<BR>by 2 yards and reduces the energy cost of<BR>your Blind and Sap abilities by 25%.",
"Increases the range of your Blind and Sap abilities<BR>by 5 yards and reduces the energy cost of<BR>your Blind and Sap abilities by 50%."
},


//Camouflage - Subtlety
{"Camouflage",
"Increases your speed while stealthed by 5%<BR>and reduces the cooldown of your Stealth ability by 2 sec.",
"Increases your speed while stealthed by 10%<BR>and reduces the cooldown of your Stealth ability by 4 sec.",
"Increases your speed while stealthed by 15%<BR>and reduces the cooldown of your Stealth ability by 6 sec."
},

//Elusiveness - Subtlety
{"Elusiveness",
"Reduces the cooldown of your Vanish and Blind<BR>abilities by 30 sec. and your Cloak of Shadows ability by 15 sec.",
"Reduces the cooldown of your Vanish and Blind<BR>abilities by 60 sec. and your Cloak of Shadows ability by 30 sec."
},


//Ghostly Strike - Subtlety
{"Ghostly Strike",
"<span style=text-align:left;float:left;>40 Energy</span><span style=text-align:right;float:right;>5 yd range</span><br><span style=text-align:left;float:left;>Instant</span><span style=text-align:right;float:right;>20 sec cooldown</span><br><span style='text-align:left;float:left;'>Requires Melee Weapon</span><br>A strike that deals 125% weapon damage and increases your<BR>chance to dodge by 15% for 7 sec.<BR>Awards 1 combo point."
},

//Serrated Blades - Subtlety
{"Serrated Blades",
"Causes your attacks to ignore 2.67% of your target's Armor<BR>and increases the damage dealt by your Rupture ability by 10%.<BR>The amount of Armor reduced increases with your level.",
"Causes your attacks to ignore 5.34% of your target's Armor<BR>and increases the damage dealt by your Rupture ability by 20%.<BR>The amount of Armor reduced increases with your level.",
"Causes your attacks to ignore 8% of your target's Armor<BR>and increases the damage dealt by your Rupture ability by 30%.<BR>The amount of Armor reduced increases with your level."
},

//Setup - Subtlety
{"Setup",
"Gives you a 33% chance to add a combo point to your<BR>target after dodging their attack or fully resisting one<BR>of their spells.<BR>This cannot happen more than once per second.",
"Gives you a 66% chance to add a combo point to your<BR>target after dodging their attack or fully resisting one<BR>of their spells.<BR>This cannot happen more than once per second.",
"Gives you a 100% chance to add a combo point to your<BR>target after dodging their attack or fully resisting one<BR>of their spells.<BR>This cannot happen more than once per second."
},

//Initiative - Subtlety
{"Initiative",
"Gives you a 33% chance to add an additional<BR>combo point to your target when using your Ambush,<BR>Garrote, or Cheap Shot ability.",
"Gives you a 66% chance to add an additional<BR>combo point to your target when using your Ambush,<BR>Garrote, or Cheap Shot ability.",
"Gives you a 100% chance to add an additional<BR>combo point to your target when using your Ambush,<BR>Garrote, or Cheap Shot ability."
},

//Improved Ambush - Subtlety
{"Improved Ambush",
"Increases the critical strike chance of your Ambush ability by 25%.",
"Increases the critical strike chance of your Ambush ability by 50%."
},

//Heightened Senses - Subtlety
{"Heightened Senses",
"Increases your Stealth detection and reduces the chance you<BR>are hit by spells and ranged attacks by 2%.",
"Increases your Stealth detection and reduces the chance you<BR>are hit by spells and ranged attacks by 4%.<BR>More effective than Heightened Senses (Rank 1)."
},

//Preparation - Subtlety
{"Preparation",
"<span style=text-align:left;float:left;>Instant</span><span style=text-align:right;float:right;>10 min cooldown</span><br>When activated, this ability immediately finishes the cooldown on your<BR>Evasion, Sprint, Vanish, Cold Blood and Shadowstep abilities."
},

//Dirty Deeds - Subtlety
{"Dirty Deeds",
"Reduces the Energy Cost of your Cheap Shot and Garrote abilities by 10.<BR>Additionally, your special abilities cause 10% more damage<BR>against targets below 35% health.",
"Reduces the Energy Cost of your Cheap Shot and Garrote abilities by 20.<BR>Additionally, your special abilities cause 20% more damage<BR>against targets below 35% health."
},

//Hemorrhage - Subtlety
{"Hemorrhage",
"<span style=text-align:left;float:left;>35 Energy</span><span style=text-align:right;float:right;>Melee range</span><br>Instant<br>Requires Melee Weapon<br>An instant strike that deals 110% weapon damage and causes the target<BR>to hemorrhage, increasing any Physical damage dealt to<BR>the target by up to 75.<BR>Lasts 10 charges or 15 sec.<BR>Awards 1 combo point.<br><br>"
},

//Master of Subtlety - Subtlety
{"Master of Subtlety",
"Attacks made while stealthed and for 6 seconds after<BR>breaking stealth cause an additional 4% damage.",
"Attacks made while stealthed and for 6 seconds after<BR>breaking stealth cause an additional 7% damage.",
"Attacks made while stealthed and for 6 seconds after<BR>breaking stealth cause an additional 10% damage."
},


//Deadliness - Subtlety
{"Deadliness",
"Increases your Attack Power by 2%.",
"Increases your Attack Power by 4%.",
"Increases your Attack Power by 6%.",
"Increases your Attack Power by 8%.",
"Increases your Attack Power by 10%."
},

//Enveloping Shadows - Subtlety
{"Enveloping Shadows",
"Reduces the damage taken by area of effect attacks by 10%.",
"Reduces the damage taken by area of effect attacks by 20%.",
"Reduces the damage taken by area of effect attacks by 30%."
},

//Premeditation - Subtlety
{"Premeditation",
"30 yd range<br><span style=text-align:left;float:left;>Instant</span><span style=text-align:right;float:right;>2 min cooldown</span><br><span style=color:eb0504>Requires Stealth</span><br>When used, adds 2 combo points to your target.<BR>You must add to or use those combo points within 20 sec<BR>or the combo points are lost."
},

//Cheat Death - Subtlety
{"Cheat Death",
"You have a 33% chance that an attack which would otherwise<BR>kill you will instead reduce you to 10% of your maximum health.<BR>In addition, all damage taken will be reduced by up to 90% for<BR>3 sec (modified by resilience).<BR>This effect cannot occur more than once per minute.",
"You have a 66% chance that an attack which would otherwise<BR>kill you will instead reduce you to 10% of your maximum health.<BR>In addition, all damage taken will be reduced by up to 90% for<BR>3 sec (modified by resilience).<BR>This effect cannot occur more than once per minute.",
"You have a 100% chance that an attack which would otherwise<BR>kill you will instead reduce you to 10% of your maximum health.<BR>In addition, all damage taken will be reduced by up to 90% for<BR>3 sec (modified by resilience).<BR>This effect cannot occur more than once per minute."
},

//Sinister Calling - Subtlety
{"Sinister Calling",
"Increases your total Agility by 3% and increases the<BR>percentage damage bonus of Backstab and Hemorrhage<BR>by an additional 2%.",
"Increases your total Agility by 6% and increases the<BR>percentage damage bonus of Backstab and Hemorrhage<BR>by an additional 4%.",
"Increases your total Agility by 9% and increases the<BR>percentage damage bonus of Backstab and Hemorrhage<BR>by an additional 6%.",
"Increases your total Agility by 12% and increases the<BR>percentage damage bonus of Backstab and Hemorrhage<BR>by an additional 8%.",
"Increases your total Agility by 15% and increases the<BR>percentage damage bonus of Backstab and Hemorrhage<BR>by an additional 10%."
},

//Waylay - Subtlety
{"Waylay",
"Your Ambush critical hits have a 50% chance to<BR>reduce the target's melee and ranged attack speed<BR>by 20%, movement speed by 70% for 8 sec.",
"Your Ambush critical hits have a 100% chance to<BR>reduce the target's melee and ranged attack speed<BR>by 20%, movement speed by 70% for 8 sec."
},

//Honor Among Thieves - Subtlety
{"Honor Among Thieves",
"When anyone in your group critically hits with a damage or<BR>healing spell or ability, you have a 33% chance to gain<BR>a combo point on your current target.<BR>This effect cannot occur more than once every second.",
"When anyone in your group critically hits with a damage or<BR>healing spell or ability, you have a 66% chance to gain<BR>a combo point on your current target.<BR>This effect cannot occur more than once every second.",
"When anyone in your group critically hits with a damage or<BR>healing spell or ability, you have a 100% chance to gain<BR>a combo point on your current target.<BR>This effect cannot occur more than once every second."
},

//Shadowstep - Subtlety
{"Shadowstep",
"<span style=text-align:left;float:left;>10 Energy</span><span style=text-align:right;float:right;>25 yd range</span><br><span style=text-align:left;float:left;>Instant</span><span style=text-align:right;float:right;>30 sec cooldown</span><br>Attempts to step through the shadows and reappear behind your enemy and<BR>increases movement speed by 70% for 3 sec.<BR>The damage of your next ability is increased by 20% and the threat<BR>caused is reduced by 50%.<BR>Lasts 10 sec."
},

//Filthy Tricks - Subtlety
{"Filthy Tricks",
"Reduces the cooldown of your Tricks of the Trade<BR>and Distract abilities by 5 secs and Preparation by 2.5 min.",
"Reduces the cooldown of your Tricks of the Trade<BR>and Distract abilities by 10 secs and Preparation by 5 min."
},

//Slaughter form the Shadows - Subtlety
{"Slaughter form the Shadows",
"Reduces the energy cost of your Backstab and<BR>Ambush abilities by 3 and the energy cost of<BR>your Hemorrhage by 1.",
"Reduces the energy cost of your Backstab and<BR>Ambush abilities by 6 and the energy cost of<BR>your Hemorrhage by 2.",
"Reduces the energy cost of your Backstab and<BR>Ambush abilities by 9 and the energy cost of<BR>your Hemorrhage by 3.",
"Reduces the energy cost of your Backstab and<BR>Ambush abilities by 12 and the energy cost of<BR>your Hemorrhage by 4.",
"Reduces the energy cost of your Backstab and<BR>Ambush abilities by 15 and the energy cost of<BR>your Hemorrhage by 5."
},

//Shadow Dance - Subtlety
{"Shadow Dance",
"<span style=text-align:left;float:left;>Instant</span><span style=text-align:right;float:right;>2 min cooldown</span><br>Enter the Shadow Dance, allowing the use of Sap, Garrotte, Ambush,<BR>Cheap Shot, Premeditation, Pickpocket and Disarm Trap regardless<BR>of being stealthed."
}};

}